﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    /// 环境扩展类
    /// </summary>
    public partial class EnvironmentEx
    {
        /// <summary>
        /// SupportedOSPlatform-windows
        /// </summary>
        public const string WINDOWS = "windows";

        /// <summary>
        /// SupportedOSPlatform-linux
        /// </summary>
        public const string LINUX = "linux";


        static EnvironmentEx()
        {
#if CORE
            string mfileName = Environment.ProcessPath;
#else
            string mfileName = System.IO.Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName);
#endif

            if (mfileName == null)
            {
                return;
            }

            mfileName = mfileName.ToLower();
            if (mfileName.Contains("w3wp.exe") || mfileName.Contains("iisexpress.exe"))
            {
                _appType = AppType.WebApp;
            }

            Assembly assembly = Assembly.GetEntryAssembly();
            if (assembly != null)
            {
                _appName = assembly.GetName().Name;
            }
        }


        private static string _appName;
        /// <summary>
        /// 获取或设置当前应用程序名称
        /// </summary>
        public static string AppName
        {
            get { return _appName; }
            set { _appName = value; }
        }


        private static readonly AppType _appType = AppType.Exe;
        /// <summary>
        /// 获取当前环境是否是WebApp环境[true:WebApp;false:exe]
        /// </summary>
        public static AppType AppType
        {
            get
            {
                return _appType;
            }
        }

        ///// <summary>
        ///// 使用指定的应用程序配置文件作为 System.Configuration.Configuration 对象打开以允许读或写操作。
        ///// </summary>
        ///// <returns>System.Configuration.Configuration</returns>
        //public static System.Configuration.Configuration OpenWebConfiguration()
        //{
        //    System.Configuration.Configuration config;
        //    if (_appType == AppType.WebApp)
        //    {
        //        config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
        //    }
        //    else
        //    {
        //        config = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None);
        //    }

        //    return config;
        //}


        /// <summary>
        /// 获取当前操作系统类型
        /// </summary>
        public static OSPlatformID OS
        {
            get
            {
                OSPlatformID os;
                switch (Environment.OSVersion.Platform)
                {
                    case PlatformID.Win32NT:
                    case PlatformID.Win32S:
                    case PlatformID.Win32Windows:
                        os = OSPlatformID.Win;
                        break;
                    case PlatformID.Unix:
                        os = OSPlatformID.Linux_Unix;
                        break;
                    case PlatformID.MacOSX:
                        os = OSPlatformID.MacOS;
                        break;
                    default:
                        os = OSPlatformID.Other;
                        break;
                }

                return os;
            }
        }

        /// <summary>
        /// 将PlatformID转换为OSPlatformID
        /// </summary>
        /// <param name="platformID">PlatformID</param>
        /// <returns>OSPlatformID</returns>
        public static OSPlatformID CovnerTo(PlatformID platformID)
        {
            OSPlatformID os;
            switch (platformID)
            {
                case PlatformID.Win32NT:
                case PlatformID.Win32S:
                case PlatformID.Win32Windows:
                    os = OSPlatformID.Win;
                    break;
                case PlatformID.Unix:
                    os = OSPlatformID.Linux_Unix;
                    break;
                case PlatformID.MacOSX:
                    os = OSPlatformID.MacOS;
                    break;
                default:
                    os = OSPlatformID.Other;
                    break;
            }

            return os;
        }

        /// <summary>
        /// 判断当前操作系统平台是否是Windows平台[是返回true,不是返回false]
        /// </summary>
        /// <returns>是返回true,不是返回false</returns>
        public static bool IsWindowPlatform()
        {
            return EnvironmentEx.OS == OSPlatformID.Win;
        }

        /// <summary>
        /// 判断当前操作系统平台是否是Linux或Unix平台[是返回true,不是返回false]
        /// </summary>
        /// <returns>是返回true,不是返回false</returns>
        public static bool IsLinuxOrUnixPlatform()
        {
            return EnvironmentEx.OS == OSPlatformID.Linux_Unix;
        }

        /// <summary>
        /// 判断当前操作系统平台是否是MacOS平台[是返回true,不是返回false]
        /// </summary>
        /// <returns>是返回true,不是返回false</returns>
        public static bool IsMacOSPlatform()
        {
            return EnvironmentEx.OS == OSPlatformID.MacOS;
        }


        //CPU小端:高位数据存放在高地址,低位数据存放在低地址
        //CPU大端:高位数据存放在低地址,低位数据存放在高地址

        /// <summary>
        /// 当前CPU类型
        /// </summary>
        private static ByteSequence? _cpuType = null;
        /// <summary>
        /// 获取当前当前CPU类型
        /// </summary>
        public static ByteSequence CpuType
        {
            get
            {
                if (_cpuType == null)
                {
                    int i = 1;
                    byte[] buffer = BitConverter.GetBytes(i);
                    if (buffer[0] == 1)
                    {
                        //小端
                        _cpuType = ByteSequence.LittleEndian;
                    }
                    else
                    {
                        //大端
                        _cpuType = ByteSequence.LargeEndian;
                    }
                }
                return _cpuType.Value;
            }
        }


        /// <summary>
        /// 获取环境变量列表
        /// </summary>
        /// <returns>环境变量集合</returns>
        public static List<string> GetEnvPaths()
        {
            char[] trimChas = new char[] { '"', '\'', ' ' };
            List<string> envPathList = new List<string>();
            IDictionary dic = Environment.GetEnvironmentVariables();
            var os = Environment.OSVersion.Platform;
            string tmpStr, pathRoot;
            foreach (string item in dic.Values)
            {
                tmpStr = item.Trim(trimChas);
                if (tmpStr.Contains(';'))
                {
                    string[] subItems = tmpStr.Split(';');
                    for (int i = 0; i < subItems.Length; i++)
                    {
                        pathRoot = Path.GetPathRoot(subItems[i]);
                        if (!string.IsNullOrWhiteSpace(pathRoot))
                        {
                            if (os == PlatformID.Win32NT)
                            {
                                if (pathRoot != "\\" && pathRoot != "/")
                                {
                                    envPathList.Add(subItems[i]);
                                }
                            }
                            else
                            {
                                if (pathRoot == "\\" || pathRoot == "/")
                                {
                                    envPathList.Add(subItems[i]);
                                }
                            }
                        }
                    }
                }
                else
                {
                    pathRoot = Path.GetPathRoot(item);
                    if (!string.IsNullOrWhiteSpace(pathRoot))
                    {
                        if (os == PlatformID.Win32NT)
                        {
                            if (pathRoot != "\\" && pathRoot != "/")
                            {
                                envPathList.Add(item);
                            }
                        }
                        else
                        {
                            if (pathRoot == "\\" || pathRoot == "/")
                            {
                                envPathList.Add(item);
                            }
                        }
                    }
                }
            }

            return envPathList;
        }

        /// <summary>
        /// 从环境变量路径中获取指定名称文件的全路径,获取失败返回null
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <returns>指定名称文件的全路径</returns>
        /// <exception cref="ArgumentNullException">文件名为null异常</exception>
        public static string GetFilePathFromEnvPath(string fileName)
        {
            if (string.IsNullOrWhiteSpace(fileName))
            {
                throw new ArgumentNullException(nameof(fileName));
            }

            char[] trimChas = new char[] { '"', '\'', ' ' };
            IDictionary dic = Environment.GetEnvironmentVariables();
            var os = Environment.OSVersion.Platform;
            string appExeFilePath, tmpStr, pathRoot;

            foreach (string item in dic.Values)
            {
                tmpStr = item.Trim(trimChas);
                if (tmpStr.Contains(';'))
                {
                    string[] subItems = tmpStr.Split(';');
                    for (int i = 0; i < subItems.Length; i++)
                    {
                        pathRoot = Path.GetPathRoot(subItems[i]);
                        if (!string.IsNullOrWhiteSpace(pathRoot))
                        {
                            if (os == PlatformID.Win32NT)
                            {
                                if (pathRoot != "\\" && pathRoot != "/")
                                {
                                    appExeFilePath = PathEx.Combine(PathType.Local, subItems[i], fileName);
                                    if (File.Exists(appExeFilePath))
                                    {
                                        return appExeFilePath;
                                    }
                                }
                            }
                            else
                            {
                                if (pathRoot == "\\" || pathRoot == "/")
                                {
                                    appExeFilePath = PathEx.Combine(PathType.Local, subItems[i], fileName);
                                    if (File.Exists(appExeFilePath))
                                    {
                                        return appExeFilePath;
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    pathRoot = Path.GetPathRoot(item);
                    if (!string.IsNullOrWhiteSpace(pathRoot))
                    {
                        if (os == PlatformID.Win32NT)
                        {
                            if (pathRoot != "\\" && pathRoot != "/")
                            {
                                appExeFilePath = PathEx.Combine(PathType.Local, item, fileName);
                                if (File.Exists(appExeFilePath))
                                {
                                    return appExeFilePath;
                                }
                            }
                        }
                        else
                        {
                            if (pathRoot == "\\" || pathRoot == "/")
                            {
                                appExeFilePath = PathEx.Combine(PathType.Local, item, fileName);
                                if (File.Exists(appExeFilePath))
                                {
                                    return appExeFilePath;
                                }
                            }
                        }
                    }
                }
            }

            return null;
        }





        #region 主机内存信息

        /// <summary>
        /// 内存信息结构体
        /// </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 64)]
        private struct MEMORY_INFO
        {
            /// <summary>
            /// 当前结构体大小
            /// </summary>
            public uint Length;

            /// <summary>
            /// 当前内存使用率
            /// </summary>
            public uint MemoryLoad;

            /// <summary>
            /// 总计物理内存大小
            /// </summary>
            public long TotalPhys;

            /// <summary>
            /// 可用物理内存大小
            /// </summary>
            public long AvailPhys;

            /// <summary>
            /// 总计交换文件大小
            /// </summary>
            public long TotalSwapFile;

            /// <summary>
            /// 可用交换文件大小
            /// </summary>
            public long AvailSwapFile;

            /// <summary>
            /// 总计虚拟内存大小
            /// </summary>
            public long TotalVirtual;

            /// <summary>
            /// 可用虚拟内存大小
            /// </summary>
            public long AvailVirtual;

            /// <summary>
            /// 保留 这个值始终为0
            /// </summary>
            public long Extended;
        }

        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GlobalMemoryStatusEx(ref MEMORY_INFO mi);

        private static void GlobalMemoryStatusForLinux(ref MEMORY_INFO mi)
        {
            /*********************************************************************************************
             * [root@localhost ~]# free -b
             *               total        used        free      shared  buff/cache   available
             * Mem:     6988046336   743624704  5555417088    14057472   689004544  5848924160
             * Swap:    8468295680           0  8468295680
             * [root@localhost ~]# 
             *********************************************************************************************/

            string text = ProcessEx.ExecuteCommand(@"free -b");
            string[] linsArr = text.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            char[] splitChs = new char[] { ' ' };

            string[] firstLineCols = linsArr[1].Split(splitChs, StringSplitOptions.RemoveEmptyEntries);
            mi.TotalPhys = long.Parse(firstLineCols[1]);
            var use = long.Parse(firstLineCols[2]);
            mi.MemoryLoad = (uint)(use * 100 / mi.TotalPhys);
            mi.AvailPhys = long.Parse(firstLineCols[6]);

            string[] secondLineCols = linsArr[2].Split(splitChs, StringSplitOptions.RemoveEmptyEntries);
            mi.TotalSwapFile = long.Parse(secondLineCols[1]);
            //var use2 = long.Parse(secondLineCols[1]);
            mi.AvailSwapFile = long.Parse(secondLineCols[3]);
        }

        /// <summary>
        /// 获取主机内存信息
        /// </summary>
        /// <returns>主机内存信息</returns>
        unsafe public static MemoryInfo GetHostMemoryInfo()
        {
            MEMORY_INFO memoryStatusInfo = new MEMORY_INFO();

            if (EnvironmentEx.IsWindowPlatform())
            {
                memoryStatusInfo.Length = (uint)sizeof(MEMORY_INFO);
                GlobalMemoryStatusEx(ref memoryStatusInfo);
            }
            else
            {
                GlobalMemoryStatusForLinux(ref memoryStatusInfo);
            }

            //StringBuilder sb = new StringBuilder();

            //sb.Append("当前结构体大小:");
            //sb.AppendLine(memoryStatusInfo.dwLength.ToString());

            //sb.Append("当前内存使用率:");
            //sb.AppendLine(memoryStatusInfo.dwMemoryLoad.ToString());

            //sb.Append("总计物理内存大小:");
            //sb.AppendLine(UnitConverter.ByteToMB(memoryStatusInfo.ullTotalPhys).ToString());

            //sb.Append("可用物理内存大小:");
            //sb.Append(UnitConverter.ByteToMB(memoryStatusInfo.ullAvailPhys).ToString());
            //sb.AppendLine("MB");

            //sb.Append("总计交换文件大小:");
            //sb.Append(UnitConverter.ByteToMB(memoryStatusInfo.ullTotalPageFile).ToString());
            //sb.AppendLine("MB");

            //sb.Append("总计交换文件大小:");
            //sb.Append(UnitConverter.ByteToMB(memoryStatusInfo.ullAvailPageFile).ToString());
            //sb.AppendLine("MB");

            //sb.Append("总计虚拟内存大小:");
            //sb.Append(UnitConverter.ByteToMB(memoryStatusInfo.ullTotalVirtual).ToString());
            //sb.AppendLine("MB");

            //sb.Append("可用虚拟内存大小:");
            //sb.Append(UnitConverter.ByteToMB(memoryStatusInfo.ullAvailVirtual).ToString());
            //sb.AppendLine("MB");

            //sb.Append("保留:");
            //sb.AppendLine(memoryStatusInfo.ullAvailExtendedVirtual.ToString());

            //string str = sb.ToString();

            return new MemoryInfo(memoryStatusInfo.TotalPhys, memoryStatusInfo.AvailPhys, memoryStatusInfo.TotalSwapFile, memoryStatusInfo.AvailSwapFile);
        }

        #endregion

    }

    /// <summary>
    /// 内存信息
    /// </summary>
    public struct MemoryInfo
    {
        /// <summary>
        /// 总计物理内存大小,单位:Byte
        /// </summary>
        public readonly long TotalPhys;

        /// <summary>
        /// 可用物理内存大小,单位:Byte
        /// </summary>
        public readonly long AvailPhys;

        /// <summary>
        /// 总计交换文件大小,单位:Byte
        /// </summary>
        public readonly long TotalSwapFile;

        /// <summary>
        /// 可用交换文件大小,单位:Byte
        /// </summary>
        public readonly long AvailSwapFile;

        /// <summary>
        /// 构造函数初始化
        /// </summary>
        /// <param name="totalPhys">总计物理内存大小,单位:Byte</param>
        /// <param name="availPhys">可用物理内存大小,单位:Byte</param>
        /// <param name="totalSwapFile">总计交换文件大小,单位:Byte</param>
        /// <param name="availSwapFile">可用交换文件大小,单位:Byte</param>
        public MemoryInfo(long totalPhys, long availPhys, long totalSwapFile, long availSwapFile)
        {
            this.TotalPhys = totalPhys;
            this.AvailPhys = availPhys;
            this.TotalSwapFile = totalSwapFile;
            this.AvailSwapFile = availSwapFile;
        }
    }

}
